/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.panel;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.GetFieldsRequestMessage;
import cn.easyplatform.messages.response.FieldsUpdateResponseMessage;
import cn.easyplatform.messages.vos.datalist.ListQueryParameterVo;
import cn.easyplatform.spi.service.TaskService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.web.ext.Reloadable;
import cn.easyplatform.web.ext.ZkExt;
import cn.easyplatform.web.ext.zul.ComboboxExt;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.event.EventEntry;
import cn.easyplatform.web.task.event.FieldEntry;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.zkex.ComponentBuilderFactory;
import cn.easyplatform.web.task.zkex.list.PanelSupport;
import cn.easyplatform.web.utils.ExtUtils;
import cn.easyplatform.web.utils.PageUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Idspace;

import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class QueryPanelBuilder implements PanelSupport {

    private ListSupport listSupport;

    private List<Component> panelComponents;

    private Map<String, Component> managedComponents;

    private Map<String, ComboboxExt> ops;

    private Map<String, ComboboxExt> rps;

    private Component component;

    /**
     * @param listSupport
     */
    public QueryPanelBuilder(ListSupport listSupport) {
        this.listSupport = listSupport;
    }

    public Component build(String xml, Collection<ListQueryParameterVo> pvs) {
        Idspace space = new Idspace();
        space.setHflex("1");
        space.setVflex("1");
        component = Executions.getCurrent().createComponentsDirectly(xml,
                "zul", space, null);
        component.setAttribute("$easyplatform", listSupport.getMainHandler().getComponent().getAttribute("$easyplatform"));
        if (component instanceof HtmlBasedComponent) {
            HtmlBasedComponent xul = (HtmlBasedComponent) component;
            if (Strings.isBlank(xul.getWidth()))
                xul.setHflex("1");
            if (Strings.isBlank(xul.getHeight()))
                xul.setVflex("1");
            if (xul instanceof Grid) {
                if (xul.getSclass() == null)
                    xul.setSclass("z-form");
            }
        }
        Iterator<Component> itr = component.queryAll("*").iterator();
        panelComponents = new ArrayList<Component>();
        managedComponents = new HashMap<String, Component>();
        List<ComboboxExt> cbxs = new ArrayList<ComboboxExt>();
        while (itr.hasNext()) {
            Component c = itr.next();
            if (c.getId().startsWith("#{")) {
                panelComponents.add(c);
                if (c instanceof ZkExt)
                    ComponentBuilderFactory.getZkBuilder(this, (ZkExt) c)
                            .build();
                else PageUtils.processEventHandler(this, c, null);
//				XulElement xe = (XulElement) c;
//				if (c instanceof InputElement) {
//					xe.setEvent("query()");
//					addEventListener(c, Events.ON_OK);
//				}
                // else if (c instanceof Radiogroup || c instanceof Checkbox
                // || c instanceof Switchbox)
                // addEventListener(c, Events.ON_CHECK);
                if (pvs != null) {
                    String id = c.getId().substring(2, c.getId().indexOf("}"));
                    for (ListQueryParameterVo pv : pvs) {
                        if (id.equals(pv.getName()) && pv.getValues() != null) {
                            Iterator<Object> pvItr = pv.getValues().iterator();
                            if (pvItr.hasNext()) {
                                PageUtils.setValue(c, pvItr.next());
                                pvItr.remove();
                                break;
                            }
                        }
                    }
                }
                if (!c.getId().endsWith("}"))// 不是标准的id
                    c.setAttribute("id",
                            c.getId().substring(2, c.getId().indexOf("}")));
                c.setId(c.getId().replace("#{", "").replace("}", ""));
            } else if (c instanceof ComboboxExt) {
                ComboboxExt cbx = (ComboboxExt) c;
                if ((cbx.getType().equals("op") || cbx.getType().equals("rp"))
                        && !Strings.isBlank(cbx.getFor()))
                    cbxs.add(cbx);
            } else if (c instanceof ZkExt)
                c = ComponentBuilderFactory.getZkBuilder(this, (ZkExt) c)
                        .build();
            else PageUtils.processEventHandler(this, c, null);
            if (!Strings.isBlank(c.getId()))
                managedComponents.put(c.getId(), c);
        }
        ops = new HashMap<String, ComboboxExt>();
        rps = new HashMap<String, ComboboxExt>();
        for (ComboboxExt cbx : cbxs) {
            if (cbx.getType().equals("op")) {
                ComboboxExt newc = ExtUtils.getOp();
                Components.replace(cbx, newc);
                if (Strings.isBlank(cbx.getWidth()))
                    newc.setWidth("80px");
                else
                    newc.setWidth(cbx.getWidth());
                ops.put(cbx.getFor(), newc);
                // 如果指定值，删除不包括的项
                if (!Strings.isBlank(cbx.getValue())) {
                    String[] vs = cbx.getValue().split("\\,");
                    Iterator<Comboitem> ir = newc.getItems().iterator();
                    while (ir.hasNext()) {
                        Comboitem ci = ir.next();
                        String value = ci.getValue();
                        boolean isFind = false;
                        for (String v : vs) {
                            if (value.equals(v)) {
                                if (newc.getSelectedIndex() < 0)
                                    newc.setSelectedItem(ci);
                                isFind = true;
                                break;
                            }
                        }
                        if (!isFind)
                            ir.remove();
                    }
                }
                if (pvs != null) {
                    for (ListQueryParameterVo pv : pvs) {
                        if (cbx.getFor().equals(pv.getName())) {
                            if (pv.getOp() != null)
                                PageUtils.setValue(newc, pv.getOp());
                            break;
                        }
                    }
                }
            } else if (cbx.getType().equals("rp")) {
                ComboboxExt newc = ExtUtils.getRp();
                Components.replace(cbx, newc);
                if (Strings.isBlank(cbx.getWidth()))
                    newc.setWidth("60px");
                else
                    newc.setWidth(cbx.getWidth());
                rps.put(cbx.getFor(), newc);
                if (pvs != null) {
                    for (ListQueryParameterVo pv : pvs) {
                        if (cbx.getFor().equals(pv.getName())) {
                            if (pv.getRp() != null)
                                PageUtils.setValue(newc, pv.getRp());
                            break;
                        }
                    }
                }
            }
        }
        return space;
    }

    @Override
    public Map<String, ListQueryParameterVo> getQueryValue() {
        Map<String, ListQueryParameterVo> params = new LinkedHashMap<>();
        for (Component c : panelComponents) {
            Object value = PageUtils.getValue(c, true);
            String id = c.getId();
            if (c.getAttribute("id") != null)
                id = (String) c.getAttribute("id");
            if (value == null || value.toString().trim().equals("")) {
                Combobox cbx = ops.get(id);
                if (cbx != null) {
                    String op = cbx.getSelectedItem().getValue();
                    if (op.equals("is null") || op.equals("is not null")) {
                        String rp = null;
                        if (cbx != null)
                            rp = cbx.getSelectedItem().getValue();
                        ListQueryParameterVo qpv = new ListQueryParameterVo(id,
                                op, rp);
                        params.put(id, qpv);
                    }
                }
            } else {
                ListQueryParameterVo qpv = params.get(id);
                if (qpv == null) {
                    Combobox cbx = ops.get(id);
                    String op = null;
                    if (cbx != null)
                        op = cbx.getSelectedItem().getValue();
                    cbx = rps.get(id);
                    String rp = null;
                    if (cbx != null)
                        rp = cbx.getSelectedItem().getValue();
                    qpv = new ListQueryParameterVo(id, op, rp);
                    params.put(id, qpv);
                }
                qpv.setValue(value);
            }
        }
        return params;
    }

    @Override
    public void reset() {
        for (Component c : panelComponents)
            PageUtils.setValue(c, (Object) null);
    }

    @Override
    public void refresh(EventEntry<FieldEntry> entry) {
        TaskService ts = ServiceLocator
                .lookup(TaskService.class);
        IResponseMessage<?> resp = ts.getFields(new GetFieldsRequestMessage(
                getId(), entry.getEntry().getFields(), listSupport
                .getComponent().getId(), null));
        if (resp.isSuccess()) {
            Map<String, Object> data = ((FieldsUpdateResponseMessage) resp)
                    .getBody();
            for (Map.Entry<String, Object> e : data.entrySet()) {
                for (Component c : panelComponents) {
                    if (e.getKey().equals(c.getId())) {
                        PageUtils.setValue(c, e.getValue());
                        break;
                    }
                }
            }
        }
    }

    @Override
    public void reload(String... comps) {
        if (comps.length == 0)
            listSupport.reload();
        else {
            for (String id : comps) {
                for (Component c : panelComponents) {
                    if (c.getId().equals(id)) {
                        if (c instanceof Reloadable)
                            ((Reloadable) c).reload();
                        break;
                    }
                }
            }
        }
    }

    @Override
    public void update(String... comps) {
        if (listSupport instanceof OperableHandler)
            ((OperableHandler) listSupport).update(comps);
        else
            listSupport.getMainHandler().update(comps);
    }

    @Override
    public void save(EventEntry<Boolean> entry) {
        if (listSupport instanceof OperableHandler)
            ((OperableHandler) listSupport).save(entry);
        else
            listSupport.getMainHandler().save(entry);
    }

    @Override
    public void create(EventEntry<String> entry) {
        if (listSupport instanceof OperableHandler)
            ((OperableHandler) listSupport).create(entry);
        else
            listSupport.getMainHandler().create(entry);
    }

    @Override
    public void copy(EventEntry<String> entry) {
        if (listSupport instanceof OperableHandler)
            ((OperableHandler) listSupport).copy(entry);
        else
            listSupport.getMainHandler().copy(entry);
    }

    @Override
    public void delete(EventEntry<String> entry) {
        if (listSupport instanceof OperableHandler)
            ((OperableHandler) listSupport).delete(entry);
        else
            listSupport.getMainHandler().delete(entry);
    }

    @Override
    public void edit(EventEntry<String> entry) {
        if (listSupport instanceof OperableHandler)
            ((OperableHandler) listSupport).edit(entry);
        else
            listSupport.getMainHandler().edit(entry);
    }

    @Override
    public OperableHandler getParent() {
        if (listSupport instanceof OperableHandler)
            return ((OperableHandler) listSupport).getParent();
        else
            return listSupport.getMainHandler();
    }

    @Override
    public String getId() {
        return listSupport.getMainHandler().getId();
    }

    @Override
    public String getTaskId() {
        return listSupport.getMainHandler().getTaskId();
    }

    @Override
    public String getName() {
        return listSupport.getName();
    }

    @Override
    public Map<String, Component> getManagedComponents() {
        return managedComponents;
    }

    @Override
    public Component getComponent() {
        return component;
    }

    @Override
    public String getProcessCode() {
        return listSupport.getMainHandler().getProcessCode();
    }

    @Override
    public void setProcessCode(String code) {
    }

    @Override
    public ListSupport getList() {
        return listSupport;
    }

    @Override
    public Component getContainer() {
        return listSupport.getMainHandler().getContainer();
    }

    void addEventListener(Component comp, String evtName) {
        PageUtils.addEventListener(this, evtName, comp);
    }

    @Override
    public String[] getAccess() {
        return listSupport.getMainHandler().getAccess();
    }
}